<!-- Licensed under a BSD license. See license.html for license -->
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
    <title>WebGL - Rectangle with 2 colors using bytes</title>
    <link type="text/css" href="../resources/webgl-tutorials.css" rel="stylesheet" />
</head>

<body>
    <div id="info">
        <div class="description">
            Drag sliders to translate, rotate, and scale.
        </div>
        <a href="https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-how-it-works.html" target="_blank">WebGL
            工作原理</a>
    </div>
    <canvas id="canvas"></canvas>
    <div id="uiContainer">
        <div id="ui">
            <div id="x"></div>
            <div id="y"></div>
            <div id="angle"></div>
            <div id="scaleX"></div>
            <div id="scaleY"></div>
        </div>
    </div>
</body>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
    attribute vec2 a_position;
    attribute vec4 a_color;

    uniform mat3 u_matrix;

    varying vec4 v_color;

    void main() {
        // 将位置和矩阵相乘
        gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);

        // 直接把属性值中的数据赋给可变量
        v_color = a_color;
    }
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
    precision mediump float;

    varying vec4 v_color;

    void main() {
        gl_FragColor = v_color;
    }
</script>
<!--
for most samples webgl-utils only provides shader compiling/linking and
canvas resizing because why clutter the examples with code that's the same in every sample.
See http://webglfundamentals.org/webgl/lessons/webgl-boilerplate.html
and http://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
for webgl-utils, m3, m4, and webgl-lessons-ui.
-->
<script src="../resources/webgl-utils.js"></script>
<script src="../resources/webgl-lessons-ui.js"></script>
<script src="../resources/m3.js"></script>
<script>
    "use strict";

    function main() {
        // 获取WebGL上下文
        /** @type {HTMLCanvasElement} */
        var canvas = document.getElementById("canvas");
        var gl = canvas.getContext("webgl");
        if (!gl) {
            return;
        }

        // 创建着色程序
        var program = webglUtils.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);

        // 从着色程序中找到attribute属性值所在的位置
        var positionLocation = gl.getAttribLocation(program, "a_position");
        var colorLocation = gl.getAttribLocation(program, "a_color");

        // 从着色程序中找到Uniform属性值所在的位置
        var matrixLocation = gl.getUniformLocation(program, "u_matrix");

        // 创建存放三个2维裁剪空间点的缓存
        var positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        // 设置几何
        setGeometry(gl);

        // 给颜色数据创建一个缓冲
        var colorBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
        // 设置颜色
        setColors(gl);

        var translation = [200, 150];
        var angleInRadians = 0;
        var scale = [1, 1];

        drawScene();

        // 创建交互控制栏
        webglLessonsUI.setupSlider("#x", { value: translation[0], slide: updatePosition(0), max: gl.canvas.width });
        webglLessonsUI.setupSlider("#y", { value: translation[1], slide: updatePosition(1), max: gl.canvas.height });
        webglLessonsUI.setupSlider("#angle", { slide: updateAngle, max: 360 });
        webglLessonsUI.setupSlider("#scaleX", { value: scale[0], slide: updateScale(0), min: -5, max: 5, step: 0.01, precision: 2 });
        webglLessonsUI.setupSlider("#scaleY", { value: scale[1], slide: updateScale(1), min: -5, max: 5, step: 0.01, precision: 2 });

        function updatePosition(index) {
            return function (event, ui) {
                translation[index] = ui.value;
                drawScene();
            };
        }

        function updateAngle(event, ui) {
            var angleInDegrees = 360 - ui.value;
            angleInRadians = angleInDegrees * Math.PI / 180;
            drawScene();
        }

        function updateScale(index) {
            return function (event, ui) {
                scale[index] = ui.value;
                drawScene();
            };
        }

        // 绘制场景
        function drawScene() {
            webglUtils.resizeCanvasToDisplaySize(gl.canvas);

            // 告诉WebGL怎样把提供的gl_Position裁剪空间坐标对应到画布像素坐标（屏幕空间）
            gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

            // 清空画布
            gl.clear(gl.COLOR_BUFFER_BIT);

            // 告诉它用我们之前写好的着色程序（一个着色器对）
            gl.useProgram(program);

            // 启用对应属性
            gl.enableVertexAttribArray(positionLocation);

            // 将绑定点绑定到缓冲数据（positionBuffer）
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

            // 诉属性怎么从positionBuffer中读取数据(ARRAY_BUFFER)
            var size = 2;          // 每次迭代运行提取两个单位数据
            var type = gl.FLOAT;   // 每个单位的数据类型是32位浮点型
            var normalize = false; // 不需要归一化数据
            var stride = 0;        // 0 = 移动单位数量 * 每个单位占用内存（sizeof(type)）每次迭代运行运动多少内存到下一个数据开始点
            var offset = 0;        // 从缓冲起始位置开始读取
            gl.vertexAttribPointer(
                positionLocation, size, type, normalize, stride, offset);

            // 启用颜色属性
            gl.enableVertexAttribArray(colorLocation);

            // 绑定颜色缓冲
            gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);

            // 告诉颜色属性怎么从 colorBuffer (ARRAY_BUFFER) 中读取颜色值
            var size = 4;                 // 每次迭代使用四个单位数据
            var type = gl.UNSIGNED_BYTE;  // 数据类型是8位的 UNSIGNED_BYTE 类型。
            var normalize = true;         // 标准化数据
            var stride = 0;               // 0 = 移动单位数量 * 每个单位占用内存（sizeof(type)）每次迭代运行运动多少内存到下一个数据开始点
            var offset = 0;               // 从缓冲起始位置开始读取
            gl.vertexAttribPointer(
                colorLocation, size, type, normalize, stride, offset);

            // 计算矩阵
            var matrix = m3.projection(gl.canvas.clientWidth, gl.canvas.clientHeight);
            matrix = m3.translate(matrix, translation[0], translation[1]);
            matrix = m3.rotate(matrix, angleInRadians);
            matrix = m3.scale(matrix, scale[0], scale[1]);

            // 设置着色程序矩阵
            gl.uniformMatrix3fv(matrixLocation, false, matrix);

            // 绘制几何体
            var primitiveType = gl.TRIANGLES;
            var offset = 0;
            var count = 6;
            gl.drawArrays(primitiveType, offset, count);
        }
    }


    // 定义一个矩形填充到缓冲里
    function setGeometry(gl) {
        gl.bufferData(
            gl.ARRAY_BUFFER,
            new Float32Array([
                -150, -100,
                150, -100,
                -150, 100,
                150, -100,
                -150, 100,
                150, 100]),
            gl.STATIC_DRAW);
    }

    // 给矩形的两个三角形
    // 设置颜色值并发到缓冲
    function setColors(gl) {
        // 设置两个随机颜色
        var r1 = Math.random() * 256; // 0 到 255.99999 之间
        var b1 = Math.random() * 256; // 这些数据
        var g1 = Math.random() * 256; // 在存入缓冲时
        var r2 = Math.random() * 256; // 将被截取成
        var b2 = Math.random() * 256; // Uint8Array 类型
        var g2 = Math.random() * 256;

        gl.bufferData(
            gl.ARRAY_BUFFER,
            new Uint8Array([   // Uint8Array
                r1, b1, g1, 255,
                r1, b1, g1, 255,
                r1, b1, g1, 255,
                r2, b2, g2, 255,
                r2, b2, g2, 255,
                r2, b2, g2, 255]),
            gl.STATIC_DRAW);
    }

    main();
</script>

</html>